const OAuth = require('co-wechat-oauth');

module.exports = function (config, app) {

    if (!config.weixin || !config.weixin.webUrl || !config.weixin.appId || !config.weixin.appSecret) {
        throw new Error('weixin.webUrl, weixin.appId and weixin.appSecret is required in config');
    }

    let webUrl = app.config.weixin.webUrl;
    if (webUrl[webUrl.length - 1] === '/') {
        webUrl = webUrl.substr(0, webUrl.length - 1);
    }

    const client = new OAuth(config.weixin.appId, config.weixin.appSecret,
        async function getToken(openid) {
            try {
                const r = await app.api.clients.get('bind').getToken(`oauth/${openid}`);
                app.logger.info("get token", openid, r);
                return r;
            } catch (e) {
                if (e.status === 404) {
                    return null;
                }
                throw e;
            }
        },
        async function setToken(openid, token) {
            app.logger.info("set token", openid, token);
            await app.api.clients.get('bind').setToken(`oauth/${openid}`, token);
        }
    );

    return async function (ctx, next) {
        if (ctx.path === '/user/login' && ctx.method === 'GET') {
            const redirect = `${webUrl}/user/wx-redirect?r=${encodeURIComponent(ctx.query.r || '')}`;
            const url = client.getAuthorizeURL(redirect, '1', 'snsapi_userinfo');
            ctx.logger.info("Weixin redirect url", url);
            ctx.redirect(url);
        } else if (ctx.path === '/user/wx-redirect' && ctx.method === 'GET') {
            ctx.logger.info('weixin redirect code', ctx.query.code);
            var token = await client.getAccessToken(ctx.query.code);
            ctx.logger.info('weixin token', token);
            const userInfo = await client.getUser(token.data.openid);
            ctx.logger.info('weixin user info', userInfo);
            await ctx.api.bind.setWeixinUserInfo(token.data.openid, userInfo);

            ctx.session.token = token.data.access_token;
            ctx.session.openId = token.data.openid;

            ctx.redirect(ctx.query.r || '/user/info');
        } else if (ctx.path === '/user/logout') {
            ctx.session = null;
            ctx.redirect(ctx.query.r || '/user/info');
        } else if (ctx.path === '/redirect/miniProgram') {
            if (ctx.session && ctx.session.openId) {
                if (!ctx.weixin) {
                    ctx.weixin = {};
                }
                const user = await ctx.api.bind.getWeixinUserInfo(ctx.session.openId);
                if (!user || !user.unionid) {
                    const userInfo = await client.getUser(ctx.session.openId);
                    ctx.logger.info('weixin user info', userInfo);
                    await ctx.api.bind.setWeixinUserInfo(ctx.session.openId, userInfo);
                }
                ctx.weixin.openId = ctx.session.openId;
                ctx.weixin.accessToken = ctx.session.token;
                ctx.weixin.oauth = client;
                await next();
            } else {
                ctx.redirect(`/user/login?r=${encodeURIComponent(ctx.originalUrl)}`);
            }
        } else {
            if (ctx.session && ctx.session.openId) {
                if (!ctx.weixin) {
                    ctx.weixin = {};
                }
                ctx.weixin.openId = ctx.session.openId;
                ctx.weixin.accessToken = ctx.session.token;
                ctx.weixin.oauth = client;
                await next();
            } else {
                ctx.redirect(`/user/login?r=${encodeURIComponent(ctx.originalUrl)}`);
            }
        }
    };
}
